//
//  Emoticon.swift
//  emotion
//
//  Created by 张衡 on 15/8/9.
//  Copyright © 2015年 张衡. All rights reserved.
//

import UIKit

/**
1. Emoticons.bundle的根目录中有一个 emoticons.plist
packages数组的每一项字典中的 id 对应的是每一套表情的目录名

2. 每一个表情目录下，都有一个 info.plist 文件 根目录是字典

group_name_cn 记录的表情包的 中文 名字

emoticons 数组，记录的整套表情的数组 (数组中放字典，）

3. 表情字典信息
chs:    定义的发布微博以及网络传输使用的微博文字字符串
png:    在客户端显示的图片名称

code:   emoji要显示的16进制字符串！
*/


/// 3个表情包模型 - 从 emoticons.plist 拼接到表情包 路径加载
class EmoticonPackage: NSObject {
    
    /// 目录名
    var id: String
    
    /// 分组名
    var groupName: String = ""
    
    /// 表情数组
    var emoticons: [Emoticon]?
    
    
    // 链式响应的触发点, 默认值可以做到对之前的代码不做任何调整
    init(id: String, groupName: String = "") {
        self.id = id
        self.groupName = groupName
    }
    
    
    
    // 添加最近使用的表情 - 仅往第 0 个分组中添加
    // 疑点，未做系列判断时，为啥点了表情后，常用的不增加
    class func addFavourite(emoticon: Emoticon) {
        
        // 0. 判断是否是删除按钮
        if emoticon.removeEmoticon { // 在函数内部解决，深刻体现面向对象
            return
        }
        
        // 1. 拿到第0 个分组表情包
        var ems = packages[0].emoticons
     
        // 测试
//        ems?.append(emoticon)
//        
//        // 2. 选择表情使用标记加1
//                emoticon.times++
//        
//        ems = ems!.sort({ (e1, e2) -> Bool in
//                       return e1.times > e2.times
//                    })
//        
//        packages[0].emoticons = ems
        
        // 这样才会拼接剩余的表情，是一页一个添加，如果没有这句话，是一个一个添加
        // packages[0].appendEmptyEmotions()
        
       // print(packages[0].emoticons?.count)
        
        
        // 1.1 删除末尾删除按钮，后续对数组的操作，删除按钮不参与
        ems?.removeLast()
        
        // 2. 选择表情使用标记加1
        emoticon.times++
        
        // 3. 添加 emoticon
        // 3.1 判断数组中是否已包含此表情
        let contains = ems!.contains(emoticon)
        if !contains {
            ems?.append(emoticon)
        }
        
        
        // 4. 排序表情数组
        ems = ems!.sort({ (e1, e2) -> Bool in
            return e1.times > e2.times
        })
        
        // 排序简写
        // ems = ems!.sort{ return $0.times > $1.times }
        
        // 5. 将末尾的表情删掉 ， 始终保持21个表情
        if !contains {
            ems?.removeLast()
        }
        
        // 5.1 重新追加删除按钮
        ems?.append(Emoticon(remove: true))
        
        // 6. 重新设置表情数组
        packages[0].emoticons = ems
        
        // collectionView 的排序问题，如果是横向滚动，则竖着排，如果是垂直滚动，则横着排
    }
    
    
    
    // 0. 最近
    // 1. 默认
    // 2. emoji
    // 3. 浪小花
    
    // 避免重复加载 
    // 使用 静态 常量只允许被设置一次数值，变量的写法和单例几乎一致
    static let packages = EmoticonPackage.loadPackages()
    
    /// 类函数，加载3个表情包 + 最近表情包
    private class func loadPackages() -> [EmoticonPackage] {
        
        // 加载路径，类函数调用 bundlePath 直接用
        let path = bundlePath.stringByAppendingPathComponent("emoticons.plist")
        
        // 2、 加载 plist
        let dict = NSDictionary(contentsOfFile: path)!
        
        let array = dict["packages"] as! [[String: AnyObject]]
        
        
        var arrayM = [EmoticonPackage]()
        
        // !!! 插入最近表情包 (追加空表情，在界面占位) 首先插入！！！！
        let package = EmoticonPackage(id: "", groupName: "最近").appendEmptyEmotions()
        
        arrayM.append(package) // 最近表情包,没有参与 链式响应中的loadEmoticons()
        
        // 3、 遍历数组中的字典，其余3个表情包
        for d in array {
            
            let id = d["id"] as! String
            // 链式响应
            // 先init产生一个对象，接着直接调用对象方法，完善属性赋值，重新返回自身对象
            let package = EmoticonPackage(id: id).loadEmoticons().appendEmptyEmotions()
            
            arrayM.append(package)
        }
        
        return arrayM
        
    }
    
    
    ///  加载当前对象对应的表情数组，从 info.plist 中加载并完成完整的表情包模型信息
    /// Self （大写） 表示返回本类对象
    
    // 对象函数，所以要加对象名才可以访问路径
    private func loadEmoticons() -> Self {
        
        // 1. 路径
        let path = EmoticonPackage.bundlePath.stringByAppendingPathComponent(id).stringByAppendingPathComponent("info.plist")
        
        let dict = NSDictionary(contentsOfFile: path)!
        
        groupName = dict["group_name_cn"] as! String
        
        let array = dict["emoticons"] as! [[String: String]] // 字典数组，字典类型是String: String
        
        
        
        emoticons = [Emoticon]()
        // 2、 遍历数组 ,每隔20个表情插入一个删除表情
        var index = 0
        for d in array {
            // 将表情包的 id 传递给 表情， 方便拼接路径
            emoticons?.append(Emoticon(id: id, dict: d))
            index++
            if index == 20 {
                emoticons?.append(Emoticon(remove: true))
                index = 0
            }
        }
        return self
        
    }
    
    
    // 在表情数组中追加空白表情， 如果最后一页不是21个表情，追加空白表情，并且最后一个设成删除按钮
    private func appendEmptyEmotions() -> Self {
        
        // 判断表情数组是否存在，最近表情包没有用loadEmoticons 函数，为空，经过判断
        if emoticons == nil {
            emoticons = [Emoticon]()
        }
        
        // 判断是否整页
        let count = emoticons!.count % 21
        
        // print("已经有 \(count) 个表情")
        
        // count == 0 表示整页已不需要添加
        
        if count > 0 || emoticons!.count == 0 {
            
            for _ in count..<20 {
                emoticons?.append(Emoticon(remove: false))
            }
            
            // 最末尾加一个删除按钮
            emoticons?.append(Emoticon(remove: true))
        
        }
        
        return self
    }
    
    
    // 根据表情字符串返回对应表情
    // emoticonWithString:
    private class func emoticon(string string: String) -> Emoticon? {
        
        var emoticon: Emoticon? = nil
        // 遍历所有的表情包的表情数组
        for p in EmoticonPackage.packages {
            
            // 谓词，在 p.emoticons 数组中查找表情
            //            emoticon = p.emoticons!.filter({ (em) -> Bool in
            //                return em.chs == string
            //            }).last
            
            emoticon = p.emoticons!.filter({
                $0.chs == string
            }).last
            
            // 如果找到 emoticon 退出
            if emoticon != nil {
                break
            }
            
        }
        
        return emoticon
    }
    
    
    // 将string 生成带表情符号的属性字符串
    class func emoticonText(string: String, font: UIFont) -> NSAttributedString {
                
        // 正则 - [] 是正则 的关键字，需要转义
        let pattern = "\\[.*?\\]"
        let regex = try! NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators)
        
        // 开始匹配，matchesInString 在字符串中做任意多的匹配
        let results = regex.matchesInString(string, options: NSMatchingOptions(rawValue: 0), range: NSMakeRange(0, string.characters.count))
        
        var conut = results.count
        
        let strM = NSMutableAttributedString(string: string)
        
        // 倒着遍历，获取匹配结果
        while conut > 0 {
            let result = results[--conut]
            
            let range = result.rangeAtIndex(0)
            // 获取到表情字符串
            let emString = (string as NSString).substringWithRange(range)
            
            if let emoticon = EmoticonPackage.emoticon(string: emString) {
                
                // 根据表情，创建属性字符串
                let attrString = EmoticonAttachment.iamgeText(emoticon, font: font)
                
                // 替换 strM 中对应位置的文本
                strM.replaceCharactersInRange(range, withAttributedString: attrString)
                
            }
            
        }
        
        return strM
    }

    
    
    // 1、 加载路径 用了一个static，要用类名调用这个变量-静态
    private static let bundlePath = NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent("Emoticons.bundle")
    
    
    override var description: String {
        return "\(id) \(groupName) \(emoticons)"
    }
  
}




/// 表情模型
class Emoticon: NSObject {
    
    // 表情目录
    var id: String?
    
    // 发送给服务器的表情文字
    var chs: String?
    
    // 本地显示的图片文件名
    var png: String?
    
    // 自己拼接
    var imagePath: String {
        
        // 判断是否是图片表情
        if chs == nil {
            return ""
        }
        // bundlePath + id + png
        return EmoticonPackage.bundlePath.stringByAppendingPathComponent(id!).stringByAppendingPathComponent(png!)
    }
    
    // emoji 的代码
    var code: String? {
        didSet {
            // 扫描器
            let scanner = NSScanner(string: code!)
            
            var value: UInt32 = 0
            scanner.scanHexInt(&value)
            
            emoji = String(Character(UnicodeScalar(value)))
            
        }
    }

    // emoji 字符串，自己从code中转换
    var emoji: String?
    
    
    var times = 0
    
    
    // 删除表情标记
    var removeEmoticon = false
    
    init(remove: Bool) {
        removeEmoticon = remove
    }
    
    
    init(id: String, dict:[String: String]) {
        self.id = id
        
        super.init() // kvc设值，首先要保证对象已经创建出来
        
        setValuesForKeysWithDictionary(dict)
    }
    
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {
        
    }
    
    // kvc 每个设值，都会调用这个函数，可以用这个函数具体判断每个key值，做进一步的计算，比如进一步字典转模型
//    override func setValue(value: AnyObject?, forKey key: String) {
//        
//        print("调用setvalueforkey")
//        super.setValue(value, forKey: key)
//    }
    
    override var description: String {
        return "\(chs) \(png) \(code) \(removeEmoticon)"
    }
    
}
